package ast

import (
	"errors"
	"strconv"
	"strings"

	token "shenfu.com/stone/token"
)

type ASTNode interface {
	NumChildren() int
	GetChild(i int) (ASTNode, error)
	GetChildren() []ASTNode
	ToString() string
}

type ASTLeaf interface {
	ASTNode
	GetToken() token.Token
}

// 数字字面量
type NumberLiteral struct {
	Token token.Token
}

func (n *NumberLiteral) NumChildren() int {
	return 0
}

func (*NumberLiteral) GetChildren() []ASTNode {
	return make([]ASTNode, 0)
}

func (*NumberLiteral) GetChild(i int) (ASTNode, error) {
	return nil, errors.New("")
}

func (n *NumberLiteral) GetToken() token.Token {
	return n.Token
}

func (n *NumberLiteral) ToString() string {
	return n.Token.GetText()
}

func (n *NumberLiteral) Value() int {
	i, ok := strconv.Atoi(n.Token.GetText())
	if ok != nil {
		return 0
	}
	return i
}

// 字符串字面量
type StringLiteral struct{}

// 变量名
type Name struct {
	Token token.Token
}

func (n *Name) NumChildren() int {
	return 0
}

func (*Name) GetChildren() []ASTNode {
	return make([]ASTNode, 0)
}

func (*Name) GetChild(i int) (ASTNode, error) {
	return nil, errors.New("")
}

func (n *Name) GetToken() token.Token {
	return n.Token
}

func (n *Name) ToString() string {
	return n.Token.GetText()
}

func (n *Name) Name() string {
	return n.Token.GetText()
}

// 二元运算
type BinaryExpr struct {
	Children []ASTNode
}

func (b *BinaryExpr) NumChildren() int {
	return len(b.Children)
}

func (b *BinaryExpr) GetChildren() []ASTNode {
	return b.Children
}

func (b *BinaryExpr) GetChild(i int) (ASTNode, error) {
	if i >= len(b.Children) {
		return nil, errors.New("Out of Bound")
	}
	return b.Children[i], nil
}

func (b *BinaryExpr) ToString() string {
	builder := strings.Builder{}
	builder.WriteByte('(')
	for _, child := range b.Children {
		builder.WriteString(child.ToString())
		builder.WriteByte(' ')
	}
	builder.WriteByte(')')
	return builder.String()
}

func (b *BinaryExpr) Left() ASTNode {
	return b.Children[0]
}

func (b *BinaryExpr) Right() ASTNode {
	return b.Children[2]
}

func (b *BinaryExpr) Opration() ASTNode {
	return b.Children[1]
}

type PrimaryExpr struct{}

type NegativeExpr struct{}

type BlockStmnt struct{}

type IfStmnt struct{}

type WhileStmnt struct{}

type NullStmnt struct{}
